﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace BlackStar
{

    public class HScrollbarContentReader : ContentTypeReader<HScrollbar>
    {
        protected override HScrollbar Read(ContentReader input, HScrollbar existingInstance)
        {
            HScrollbar result = new HScrollbar();
            result.ReadContent(input);
            return result;
        }
    }

    public class HScrollbar : Scrollbar
    {
        public override void Draw()
        {
            if (!myVisible) return;

            decRect = new Rectangle(myDrawRectangle.X, myDrawRectangle.Y,
                myGui.theme.Scrollbar.Rectangles["ScrollLeft"].Width,
                myDrawRectangle.Height);
            incRect = new Rectangle(myDrawRectangle.X + myDrawRectangle.Width - myGui.theme.Scrollbar.Rectangles["ScrollRight"].Width,
                myDrawRectangle.Y,
                myGui.theme.Scrollbar.Rectangles["ScrollRight"].Width,
                myDrawRectangle.Height);
            barRect = new Rectangle(myDrawRectangle.X + decRect.Width, myDrawRectangle.Y,
                myDrawRectangle.Width - (decRect.Width + incRect.Width), myDrawRectangle.Height);
            int handleW = myGui.theme.Scrollbar.Rectangles["HandleH"].Width;

            float ratio = (float)myValue / (myMax - myMin);
            int handlePos = (int)((barRect.Width - handleW) * ratio) + barRect.X;
            handRect = new Rectangle(handlePos, myDrawRectangle.Y, handleW, myDrawRectangle.Height);

            myGui.theme.Scrollbar.Draw("ScrollLeft", decRect, this.Color);
            myGui.theme.Scrollbar.Draw("ScrollRight", incRect, this.Color);
            myGui.theme.Scrollbar.Draw("BarH", barRect, this.Color);
            myGui.theme.Scrollbar.Draw("HandleH", handRect, this.Color);

            // draw any child components.
            DrawComponents();
        }

        protected override void DoDrag()
        {
            int pos = myGui.mouse.Location.X - barRect.X;
            float ratio = ((float)pos / (float)barRect.Width);
            Value = myMin + (int)((myMax - myMin) * ratio);
        }
    }

    public class VScrollbarContentReader : ContentTypeReader<VScrollbar>
    {
        protected override VScrollbar Read(ContentReader input, VScrollbar existingInstance)
        {
            VScrollbar result = new VScrollbar();
            result.ReadContent(input);
            return result;
        }
    }

    public class VScrollbar : Scrollbar
    {
        public override void Draw()
        {
            if (!myVisible) return;

            decRect = new Rectangle(myDrawRectangle.X, myDrawRectangle.Y, myDrawRectangle.Width,
                myGui.theme.Scrollbar.Rectangles["ScrollUp"].Height);
            incRect = new Rectangle(myDrawRectangle.X, myDrawRectangle.Y + myDrawRectangle.Height -
                myGui.theme.Scrollbar.Rectangles["ScrollDown"].Height, myDrawRectangle.Width,
                myGui.theme.Scrollbar.Rectangles["ScrollDown"].Height);
            barRect = new Rectangle(myDrawRectangle.X, myDrawRectangle.Y + decRect.Height,
                myDrawRectangle.Width, myDrawRectangle.Height - (decRect.Height + incRect.Height));

            int handleH = myGui.theme.Scrollbar.Rectangles["HandleV"].Height;

            float ratio = (float)myValue / (myMax - myMin);
            int handlePos = (int)((barRect.Height - handleH) * ratio) + barRect.Y;
            handRect = new Rectangle(myDrawRectangle.X, handlePos, myDrawRectangle.Width, handleH);

            myGui.theme.Scrollbar.Draw("ScrollUp", decRect, this.Color);
            myGui.theme.Scrollbar.Draw("ScrollDown", incRect, this.Color);
            myGui.theme.Scrollbar.Draw("BarV", barRect, this.Color);
            myGui.theme.Scrollbar.Draw("HandleV", handRect, this.Color);

            // draw any child components.
            DrawComponents();
        }

        protected override void DoDrag()
        {
            int pos = myGui.mouse.Location.Y - barRect.Y;
            float ratio = ((float)pos / (float)barRect.Height);
            Value = myMin + (int)((myMax - myMin) * ratio);
        }

        public override void DoMouseScroll(MouseEventArgs e)
        {
            this.Value += e.ScrollChange;
            OnMouseScroll();
        }
    }

    public class ScrollbarContentReader : ContentTypeReader<Scrollbar>
    {
        protected override Scrollbar Read(ContentReader input, Scrollbar existingInstance)
        {
            Scrollbar result = new Scrollbar();
            result.ReadContent(input);
            return result;
        }
    }

    public class Scrollbar : Component
    {
        protected bool dragging = false;
        protected Point startDrag = Point.Zero;
        protected int startDragVal = 0;

        protected int myMax = 100;
        protected int myMin = 0;
        protected int myValue = 0;
        protected int mySmallChange = 1;
        protected int myLargeChange = 10;
        protected bool myShowButtons = true;

        // we declare these rectangles here instead of in
        // the draw code so we can check their values when 
        // the update code is running so that we can determine
        // which part of the control the mouse is over. 
        protected Rectangle incRect = Rectangle.Empty;
        protected Rectangle decRect = Rectangle.Empty;
        protected Rectangle barRect = Rectangle.Empty;
        protected Rectangle handRect = Rectangle.Empty;

        private ComponentEvent onValueChanged;
        public event ComponentEvent ValueChanged
        {
            add { onValueChanged = (ComponentEvent)Delegate.Combine(onValueChanged, value); }
            remove { onValueChanged = (ComponentEvent)Delegate.Remove(onValueChanged, value); }             
        }


        [ContentSerializer(Optional = true)]
        public int LargeChange
        {
            get { return myLargeChange; }
            set { myLargeChange = value; }
        }

        [ContentSerializer(Optional = true)]
        public int Maximum
        {
            get { return myMax; }
            set
            {
                myMax = value;
                // this will trigger a changed event.
                Value = Math.Min(myMax, myValue);
            }
        }

        [ContentSerializer(Optional = true)]
        public int Minimum
        {
            get { return myMin; }
            set
            {
                myMin = value;
                // this will trigger a changed event.
                Value = Math.Max(myMin, myValue);
            }
        }

        [ContentSerializer(Optional = true)]
        public int SmallChange
        {
            get { return mySmallChange; }
            set { mySmallChange = value; }
        }

        [ContentSerializer(Optional = true)]
        public int Value
        {
            get { return myValue; }
            set
            {
                int trimmedVal = Math.Max(myMin, Math.Min(myMax, value));
                if (myValue != trimmedVal)
                {
                    myValue = trimmedVal;
                    OnValueChanged();
                }
            }
        }

        public void OnValueChanged()
        {
            if (this.onValueChanged != null) this.onValueChanged(this);
        }

        public bool ValueChangedAssigned
        { get { return this.onValueChanged != null; } }

        protected internal override void ReadContent(ContentReader input)
        {
            base.ReadContent(input);
            myMax = input.ReadInt32();
            myMin = input.ReadInt32();
            myValue = input.ReadInt32();
        }

        public override void DoMouseDown(MouseEventArgs e)
        {
            TakeFocus();
            if (decRect.Contains(e.Location))
            { this.Value -= mySmallChange; OnMouseDown(); return; }

            if (incRect.Contains(e.Location))
            { this.Value += mySmallChange; OnMouseDown(); return; }

            if (handRect.Contains(e.Location))
            {
                dragging = true;
                startDrag = e.Location;
                startDragVal = myValue;
                OnMouseDown();
                return;
            }

            if (barRect.Contains(e.Location))
            {
                if (e.Location.Y < handRect.Y || e.Location.X < handRect.X)
                { this.Value -= myLargeChange; }
                else
                { this.Value += myLargeChange; }
            }

            OnMouseDown(); 
        }

        public override void Update(GameTime gameTime)
        {
            if (dragging)
            {
                DoDrag();
                if (!myGui.mouse.LeftButton) dragging = false;
            }

            base.Update(gameTime);
        }

        protected virtual void DoDrag() { }
    }
}
